package com.authsphere.security.configurer.social.provider;

import com.authsphere.security.common.user.EnhanceUserDetailsService;
import com.authsphere.security.configurer.social.exception.ThirdLoginException;
import com.authsphere.security.configurer.social.user.ThirdAuthorizationNotBindUserDetails;
import com.authsphere.security.configurer.social.ThirdAuthorizationAuthenticationToken;
import com.authsphere.security.configurer.social.entity.ThirdAuthorizationEntity;
import com.authsphere.security.social.common.AuthRequestFactory;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.Set;

/**
 * @program: AuthSphere
 * @description:
 * @author: YuKai Fan
 * @create: 2025/3/18 20:45
 **/
public class ThirdAuthorizationAuthenticationProvider extends AbstractThirdAuthorizationAuthenticationProvider {


    private EnhanceUserDetailsService userDetailsService;

    @Override
    protected void doAfterPropertiesSet() {
        Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
    }

    @Override
    protected final UserDetails retrieveUser(String authorizationCode, ThirdAuthorizationAuthenticationToken authentication)
            throws AuthenticationException {
        try {
            ThirdAuthorizationEntity principal = (ThirdAuthorizationEntity) authentication.getPrincipal();
            String thirdType = principal.getThirdType();
            // 根据授权码获取第三方用户信息
            AuthRequest authRequest = AuthRequestFactory.getAuthRequest(thirdType);
            if (authRequest == null) {
                throw new AuthenticationServiceException(String.format("social login error, not support %s login", thirdType));
            }
            AuthResponse<AuthUser> response = authRequest.login(AuthCallback.builder()
                    .code(authorizationCode)
                    .authorization_code(authorizationCode)
                    .auth_code(authorizationCode)
                    .oauth_token(authorizationCode)
                    .state(AuthStateUtils.createState())
                    .build());
            if (!response.ok()) {
                logger.error(" ThirdAuthorizationAuthenticationProvider third login [{}] error, reason = [{}] ", thirdType, response.getMsg());
                throw new ThirdLoginException("第三方登录失败");
            }
            AuthUser authUser = response.getData();
            String uuid = authUser.getUuid();
            String source = authUser.getSource();
            // 根据uuid获取用户信息
            UserDetails loadedUser = this.getUserDetailsService().loadUserByUuidAndSource(uuid, source);
            if (loadedUser == null) {
                return new ThirdAuthorizationNotBindUserDetails(authUser, principal);
            }
            return loadedUser;
        } catch (UsernameNotFoundException | InternalAuthenticationServiceException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new AuthenticationServiceException(ex.getMessage(), ex);
        }
    }

    @Override
    protected void additionalAuthenticationChecks(ThirdAuthorizationAuthenticationToken authentication) throws AuthenticationException {

    }

    @Override
    protected Authentication createSuccessAuthentication(Object principal, Authentication authentication,
                                                         UserDetails user) {
        return super.createSuccessAuthentication(principal, authentication, user);
    }

    public void setUserDetailsService(EnhanceUserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    protected EnhanceUserDetailsService getUserDetailsService() {
        return this.userDetailsService;
    }
}
